package com.syh.jn.scm.infrastructure.repository.impl.supplier.finance.archive;

import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.infrastructure.repository.AggregateRepoMybatisImplTmpl;
import com.syh.jn.scm.domain.supplier.repository.finance.archive.ArchiveReadRepository;
import com.syh.jn.scm.dto.supplier.finance.archive.ArchiveSettlementsVo;
import com.syh.jn.scm.dto.supplier.finance.archive.ArchiveStockVo;
import com.syh.jn.scm.dto.supplier.finance.archive.ArchiveVo;
import com.syh.jn.scm.infrastructure.repository.model.finance.archive.ArchiveModel;
import com.syh.jn.scm.infrastructure.repository.model.finance.archive.ArchiveSettlementsModel;
import com.syh.jn.scm.infrastructure.repository.model.finance.archive.ArchiveStockModel;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by soci.song on 2019/3/1.
 */
@Repository("archiveRepoMbImpl")
public class ArchiveRepoMbImpl implements ArchiveReadRepository {

  private AggregateRepoMybatisImplTmpl<ArchiveVo, ArchiveModel, Long> tmpl
          = new AggregateRepoMybatisImplTmpl.Builder()
          .listTypeClass(ArchiveVo.class)
          .modelClass(ArchiveModel.class).build();

  private AggregateRepoMybatisImplTmpl<ArchiveSettlementsVo, ArchiveSettlementsModel, Long> settlementsItemTmpl
          = new AggregateRepoMybatisImplTmpl.Builder()
          .listTypeClass(ArchiveSettlementsVo.class)
          .modelClass(ArchiveSettlementsModel.class).build();

  private AggregateRepoMybatisImplTmpl<ArchiveStockVo, ArchiveStockModel, Long> stockItemTmpl
          = new AggregateRepoMybatisImplTmpl.Builder()
          .listTypeClass(ArchiveStockVo.class)
          .modelClass(ArchiveStockModel.class).build();

  public ArchiveRepoMbImpl() {
    SQL sql = new SQL() {{
      SELECT(SQLAliasGenerateUtil.aliasGenerate(ArchiveModel.class, "archive", null),
              "account.NAME AS operatorName,account.LOGIN_ACCOUNT AS operatorAccount");
      FROM("T_FINANCE_ARCHIVE archive");
      LEFT_OUTER_JOIN("T_SYSTEM_ACCOUNT account ON archive.OPERATOR_ID = account.ID");
    }};

    this.tmpl.setQuerySql(sql);
    final Map<String, String> parseMap = new HashMap<>();
    parseMap.put("operatorId", "account.ID");
    parseMap.put("operatorName", "account.NAME");
    parseMap.put("operatorAccount", "account.LOGIN_ACCOUNT");
    parseMap.put("id", "archive.ID");
    parseMap.put("businessEntityId", "archive.BUSINESS_ENTITY_ID");
    parseMap.put("archiveEndTimeStamp", "archive.ARCHIVE_END_TIME_STAMP");
    parseMap.put("createTimeStamp", "archive.CREATE_TIME_STAMP");
    this.tmpl.setWrapperParseMethods((propertyName -> {
      return parseMap.get(propertyName);
    }));

    SQL settlementsSql = new SQL() {{
      SELECT(SQLAliasGenerateUtil.aliasGenerate(ArchiveSettlementsModel.class, "item", null),
              "CASE item.CUSTOMER_TYPE WHEN 0 THEN upstream.NAME WHEN 1 THEN downstream.NAME WHEN 2 THEN logistics.NAME END AS customerName",
              "archive.ARCHIVE_END_TIME_STAMP AS archiveEndTimeStamp");
      FROM("T_FINANCE_ARCHIVE archive");
      INNER_JOIN("T_FINANCE_ARCHIVE_SETTLEMENTS item ON archive.ID = item.ARCHIVE_ID");
      LEFT_OUTER_JOIN("T_BASE_UPSTREAM upstream ON item.CUSTOMER_TYPE = 0 AND item.CUSTOMER_ID = upstream.ID");
      LEFT_OUTER_JOIN("T_BASE_DOWNSTREAM downstream ON item.CUSTOMER_TYPE = 1 AND item.CUSTOMER_ID = downstream.ID");
      LEFT_OUTER_JOIN("T_BASE_LOGISTICS logistics ON item.CUSTOMER_TYPE = 2 AND item.CUSTOMER_ID = logistics.ID");
    }};

    final Map<String, String> settlementsParseMap = new HashMap<>();
    settlementsParseMap.put("businessEntityId", "archive.BUSINESS_ENTITY_ID");
    settlementsParseMap.put("archiveId", "item.ARCHIVE_ID");
    settlementsParseMap.put("customerType", "item.CUSTOMER_TYPE");
    settlementsParseMap.put("customerId", "item.CUSTOMER_ID");
    settlementsParseMap.put("archiveEndTimeStamp", "archive.ARCHIVE_END_TIME_STAMP");
    this.settlementsItemTmpl.setQuerySql(settlementsSql);
    this.settlementsItemTmpl.setWrapperParseMethods((propertyName -> {
      return settlementsParseMap.get(propertyName);
    }));


    SQL stockSql = new SQL() {{
      SELECT(SQLAliasGenerateUtil.aliasGenerate(ArchiveStockModel.class, "item", null),
              "goods.CODE AS goodsCode,goods.NAME AS goodsName,goods.CATEGORY_NAME AS goodsCategoryName",
              "goods.SPEC_NAME AS goodsSpecName,goods.UNITS AS goodsUnits",
              "depot.NAME AS depotName",
              "archive.ARCHIVE_END_TIME_STAMP AS archiveEndTimeStamp");
      FROM("T_FINANCE_ARCHIVE archive");
      INNER_JOIN("T_FINANCE_ARCHIVE_STOCK item ON archive.ID = item.ARCHIVE_ID");
      LEFT_OUTER_JOIN("T_BASE_GOODS goods ON item.GOODS_ID = goods.ID");
      LEFT_OUTER_JOIN("T_BASE_STOREHOUSE depot ON item.DEPOT_ID = depot.ID");
    }};

    final Map<String, String> stockParseMap = new HashMap<>();
    stockParseMap.put("businessEntityId", "archive.BUSINESS_ENTITY_ID");
    stockParseMap.put("archiveId", "item.ARCHIVE_ID");
    stockParseMap.put("goodsId", "item.GOODS_ID");
    stockParseMap.put("goodsName", "goods.GOODS_NAME");
    stockParseMap.put("goodsCode", "goods.GOODS_CODE");
    stockParseMap.put("depotId", "item.DEPOT_ID");
    stockParseMap.put("depotName", "depot.NAME");
    stockParseMap.put("archiveEndTimeStamp", "archive.ARCHIVE_END_TIME_STAMP");
    this.stockItemTmpl.setQuerySql(stockSql);
    this.stockItemTmpl.setWrapperParseMethods((propertyName -> {
      return stockParseMap.get(propertyName);
    }));
  }

  @Override
  public ArchiveVo getById(Long id) {
    ArchiveVo vo = tmpl.getById(id);
    if (vo != null) {
      vo.setSettlementsItems(this.findSettlementsByArchiveId(id));
      vo.setStockItems(this.findStockByArchiveId(id));
    }
    return vo;
  }

  @Override
  public ArchiveVo getOne(Wrapper wrapper) {
    ArchiveVo vo = tmpl.getOne(wrapper);
    if (vo != null) {
      vo.setSettlementsItems(this.findSettlementsByArchiveId(vo.getId()));
      vo.setStockItems(this.findStockByArchiveId(vo.getId()));
    }
    return vo;
  }

  @Override
  public boolean contains(Long id) {
    return tmpl.getById(id) != null;
  }

  @Override
  public List<ArchiveVo> getList(Wrapper wrapper) {
    return tmpl.getList(wrapper);
  }

  @Override
  public List<ArchiveVo> findListPage(Wrapper wrapper, Integer startRow, Integer count) {
    return tmpl.findListPage(wrapper, startRow, count);
  }

  @Override
  public int getCount(Wrapper wrapper) {
    return tmpl.getCount(wrapper);
  }

  @Override
  public List<ArchiveSettlementsVo> findSettlementsByArchiveId(Long archiveId) {
    Wrapper we = Wrapper.build().append(Restrictions.eq("archiveId", archiveId));
    return settlementsItemTmpl.getList(we);
  }

  @Override
  public List<ArchiveStockVo> findStockByArchiveId(Long archiveId) {
    Wrapper we = Wrapper.build().append(Restrictions.eq("archiveId", archiveId));
    return stockItemTmpl.getList(we);
  }

  @Override
  public List<ArchiveSettlementsVo> findSettlements(Wrapper wrapper) {
    return settlementsItemTmpl.getList(wrapper);
  }

  @Override
  public List<ArchiveStockVo> findStock(Wrapper wrapper) {
    return stockItemTmpl.getList(wrapper);
  }

  @Override
  public List<ArchiveSettlementsVo> findSettlementsPage(Wrapper wrapper, Integer startRow, Integer count) {
    return settlementsItemTmpl.findListPage(wrapper, startRow, count);
  }

  @Override
  public List<ArchiveStockVo> findStockPage(Wrapper wrapper, Integer startRow, Integer count) {
    return stockItemTmpl.findListPage(wrapper, startRow, count);
  }

  @Override
  public Integer countSettlements(Wrapper we) {
    return settlementsItemTmpl.getCount(we);
  }

  @Override
  public Integer countStock(Wrapper we) {
    return stockItemTmpl.getCount(we);
  }
}
